using System;
using System.Collections.Generic;
using Client.Base;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.U2D;
using YooAsset;

namespace Client.Hotfix
{
    [UGFM(UGFMWeight.ResourceService)]
    public class ResourceService : IAwake
    {
        private readonly Dictionary<string, ResourcePackage> packageDic = new();
        public void Awake()
        {
            this.Log("ResourceComponent is Running");
        }

        public async UniTask<SceneHandle> LoadSceneAsync(string sceneName, Action<float> onProgress = null, LoadSceneMode mode = LoadSceneMode.Single)
        {
            var handle = GetGameResource().LoadSceneAsync(sceneName, mode);
            while (!handle.IsDone)
            {
                float progress = handle.Progress;
                onProgress?.Invoke(progress);
                await UniTask.Yield();
            }
            return handle;
        }

        public async UniTask<GameObject> LoadAssetWithInstantiateAsync(string assetName)
        {
            var handle = GetGameResource().LoadAssetAsync<GameObject>(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                GameObject clone = GameObject.Instantiate(handle.AssetObject) as GameObject;
                var obh = clone.AddComponent<ObHandle>();
                obh.handle = handle;
                return clone;
            }
            else
            {
                return null;
            }
        }

        public async UniTask<string> LoadTextAssetAsync(string assetName)
        {
            var handle = GetGameResource().LoadAssetAsync<TextAsset>(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                var textAsset = handle.AssetObject as TextAsset;
                string text = textAsset.text;
                handle.Release();
                return text;
            }
            else
            {
                handle.Release();
                return null;
            }

        }

        public async UniTask<byte[]> LoadBytesAssetAsync(string assetName)
        {
            var handle = GetGameResource().LoadAssetAsync<TextAsset>(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                var textAsset = handle.AssetObject as TextAsset;
                var bytes = textAsset.bytes;
                handle.Release();
                return bytes;
            }
            else
            {
                handle.Release();
                return null;
            }
        }

        public async UniTask<SpriteAtlas> LoadSpriteAtlasAsync(string assetName)
        {
            var handle = GetGameResource().LoadAssetAsync<SpriteAtlas>(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                return handle.AssetObject as SpriteAtlas;
            }
            else
            {
                return null;
            }
        }

        public async UniTask<Sprite> LoadSpriteAsync(string atlasName, string spriteName)
        {
            var atlas = await LoadSpriteAtlasAsync(atlasName);
            if (atlas != null)
            {
                return atlas.GetSprite(spriteName);
            }
            return null;
        }

        public async UniTask<string> LoadVideoPathAsync(string assetName)
        {
            var handle = GetRawResource().LoadRawFileAsync(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                string path = handle.GetRawFilePath();
                handle.Release();
                return path;
            }
            else
            {
                handle.Release();
                return null;
            }
        }

        public async UniTask<string> LoadTextRawFileWAsync(string assetName)
        {
            var handle = GetRawResource().LoadRawFileAsync(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                string text = handle.GetRawFileText();
                handle.Release();
                return text;
            }
            else
            {
                handle.Release();
                return null;
            }
        }


        public async UniTask<byte[]> LoadBytesRawFileWAsync(string assetName)
        {
            var handle = GetRawResource().LoadRawFileAsync(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                byte[] bytes = handle.GetRawFileData();
                handle.Release();
                return bytes;
            }
            else
            {
                handle.Release();
                return null;
            }
        }


        public async UniTask<AudioClip> LoadAudioClipAsync(string assetName)
        {
            var handle = GetGameResource().LoadAssetAsync<AudioClip>(assetName);
            await handle.ToUniTask();
            if (handle.Status == EOperationStatus.Succeed)
            {
                return handle.AssetObject as AudioClip;
            }
            else
            {
                return null;
            }
        }

        // 卸载所有引用计数为零的资源包。
        // 可以在切换场景之后调用资源释放方法或者写定时器间隔时间去释放。
        public async UniTask UnloadUnusedAssetsAsync()
        {
            foreach (var package in packageDic.Values)
            {
                var operation = package.UnloadUnusedAssetsAsync();
                operation.WaitForAsyncComplete(); //支持同步操作
                await operation.ToUniTask();
            }
        }
        // 强制卸载所有资源包，该方法请在合适的时机调用。
        // 注意：Package在销毁的时候也会自动调用该方法。
        public async UniTask ForceUnloadAllAssets()
        {
            foreach (var package in packageDic.Values)
            {
                var operation = package.UnloadAllAssetsAsync();
                await operation.ToUniTask();
            }
        }

        public async UniTask UnloadSceneAsync(SceneHandle handle)
        {
            if (handle.IsValid)
            {
                var operation = handle.UnloadAsync();
                await operation.ToUniTask();
            }
        }
        public void UnloadAsset(AssetHandle handle)
        {
            if (handle.IsValid)
            {
                handle.Release();
            }
        }

        private ResourcePackage GetGameResource()
        {
            if (packageDic.Count == 0)
            {
                foreach (var pk in YAPackageInfo.Setting.packages)
                {
                    if (!string.IsNullOrEmpty(pk.packageName))
                    {
                        var pack = YooAssets.GetPackage(pk.packageName);
                        packageDic[pk.packageName] = pack;
                    }
                }
            }

            foreach (var pk in YAPackageInfo.Setting.packages)
            {
                if (!pk.isRaw)
                {
                    return packageDic[pk.packageName];
                }
            }
            return null;
        }

        private ResourcePackage GetRawResource()
        {
            if (packageDic.Count == 0)
            {
                foreach (var pk in YAPackageInfo.Setting.packages)
                {
                    if (!string.IsNullOrEmpty(pk.packageName))
                    {
                        var pack = YooAssets.GetPackage(pk.packageName);
                        packageDic[pk.packageName] = pack;
                    }
                }
            }

            foreach (var pk in YAPackageInfo.Setting.packages)
            {
                if (pk.isRaw)
                {
                    return packageDic[pk.packageName];
                }
            }
            return null;
        }


    }

}
